package com.data.handler;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.data.common.Result;
import com.data.common.SystemCodeEnum;
import com.data.common.util.IPUtils;
import com.data.service.entity.EventLogFeignBO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.web.ResourceProperties;
import org.springframework.boot.autoconfigure.web.reactive.error.AbstractErrorWebExceptionHandler;
import org.springframework.boot.web.reactive.error.ErrorAttributes;
import org.springframework.context.ApplicationContext;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ReactiveHttpOutputMessage;
import org.springframework.http.codec.ServerCodecConfigurer;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.BodyInserter;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.server.*;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.Date;
import java.util.Map;


/**
 * @author zhangzhiwei
 * webflux拦截404请求
 */

@Component
@Order(-2)
@Slf4j
public class GatewayWebExceptionHandler extends AbstractErrorWebExceptionHandler {

    private String ip = "";

    /**
     * 默认 gateway 拦截管理账户
     */
    private static final String defaultUser = "admin";

    /**
     * 事件类型
     */
    private String eventType = "错误请求";

    public GatewayWebExceptionHandler(ErrorAttributes errorAttributes, ApplicationContext applicationContext,
                                      ServerCodecConfigurer serverCodecConfigurer) {
        super(errorAttributes, new ResourceProperties(), applicationContext);
        super.setMessageWriters(serverCodecConfigurer.getWriters());
        super.setMessageReaders(serverCodecConfigurer.getReaders());
    }

    @Override
    public Mono<Void> handle(ServerWebExchange exchange, Throwable throwable) {
        ServerHttpRequest request = exchange.getRequest();
        ip = IPUtils.getIpAddr(request);
        log.error("renderErrorResponse=handle=ip:{}", ip);
        return super.handle(exchange, throwable);
    }

    @Override
    protected RouterFunction<ServerResponse> getRoutingFunction(final ErrorAttributes errorAttributes) {
        return RouterFunctions.route(RequestPredicates.all(), this::renderErrorResponse);
    }

    /**
     * 异常 响应体
     *
     * @param request 请求
     * @return 响应组件
     */
    private Mono<ServerResponse> renderErrorResponse(final ServerRequest request) {
        Map<String, Object> errorAttributes = this.getErrorAttributes(request, false);
        BodyInserter<Result, ReactiveHttpOutputMessage> result;
        log.error("=renderErrorResponse=ip:{} 网关请求错误:{}", ip, JSON.toJSONString(errorAttributes));
        Integer status = (Integer) errorAttributes.get("status");
        sendEventLogAdvice(request);
        result = BodyInserters.fromValue(Result.error(SystemCodeEnum.parse(status).getMsg()));
        return ServerResponse.status(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON).body(result);
    }

    /**
     * 发送通知到 log
     *
     * @param request 请求info
     */
    private void sendEventLogAdvice(ServerRequest request) {
        EventLogFeignBO.sendEventLogAdvice(()-> EventLogFeignBO.builder()
                 .createBy(defaultUser)
                 .updateBy(defaultUser)
                 .sysOrgCode(defaultUser)
                 .createTime(new Date())
                 .updateTime(new Date())
                 .eventDesc(request.path())
                 .eventType(eventType)
                 .ipAdr(ip)
                 .reqArgs(JSONObject.toJSONString(this.getError(request)))
                 .build());
    }

}
